#include <bits/stdc++.h>
using namespace std;

int v[20][20], n, m;  // v为权值矩阵，n行m列
int f[2][600005], maxn;  // f为DP数组，双缓冲；maxn记录答案
bool b[600005];  // b数组用于记录当前状态是否已存在，去重
int q[2][600005], cnt[2];  // q为状态队列，cnt为每一轮状态个数
bool opt;  // opt为是否是本行最后一列，用于转移下一行

// 插入状态state到当前行cur中，权值为w
void insert(int cur, int state, int w)
{
    if (opt == true) {
        // 如果是本行最后一列，准备向下一行转移，需左移1位并去掉最高位
        state = state & (~(1 << m));
        state = (state << 1);
    }
    if (b[state] == false) {  // 如果这个状态是第一次遇到
        b[state] = true;
        q[cur][++cnt[cur]] = state;  // 存入状态队列
        f[cur][state] = w;
    }
    // 状态已存在，取最大值更新
    f[cur][state] = max(f[cur][state], w);
    maxn = max(maxn, f[cur][state]);  // 更新全局最大值
}

// 获取state中第k位的值（0或1）
int get(int state, int k)
{
    if (k == -1 || k == m + 1) return 0;  // 越界返回0
    return ((state >> k) & 1);  // 取第k位
}

// 返回 x * (1 << k)，即代表第k位是否选中
int val(int k, int x)
{
    return x * (1 << k);
}

int main()
{
    cin >> n >> m;  // 读入行数和列数
    for (int i = 1; i <= n; i++)  // 读入矩阵
        for (int j = 1; j <= m; j++)
            cin >> v[i][j];

    int cur = 0;  // 当前使用的缓冲区（0或1）
    insert(0, 0, 0);  // 初始状态：状态为0，权值为0

    // 遍历每个格子
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            opt = (j == m);  // 是否是本行最后一列
            maxn = 0;
            memset(b, false, sizeof(b));  // 清空标记数组

            // 遍历上一轮所有状态
            for (int k = 1; k <= cnt[cur]; k++) {
                int state = q[cur][k];  // 当前状态
                int w = f[cur][state];  // 当前状态的得分

                // 获取相邻的4个位置是否被选中
                int x = get(state, j - 2);  // j-2: 左左
                int y = get(state, j - 1);  // j-1: 左
                int z = get(state, j);      // j: 当前
                int g = get(state, j + 1);  // j+1: 右

                // 情况一：当前格子不选
                insert(cur ^ 1, state - val(j - 1, y), w);

                // 情况二：当前格子可以选
                if (v[i][j] > 0) {
                    // 不违反相邻条件才可以选
                    if (!(x && y) && !(y && z) && !(z && g) && !(x && z)) {
                        // 选中当前格子，将第j-1位置设置为1（下一轮会右移）
                        insert(cur ^ 1, state - val(j - 1, y) + val(j - 1, 1), w + v[i][j]);
                    }
                }
            }
            cnt[cur] = 0;  // 清空当前缓冲区
            cur ^= 1;  // 交换缓冲区（双缓冲DP）
        }
    }

    cout << maxn << endl;  // 输出最大值
    return 0;
}
